﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System.Data;
using System.Text;
using Util;

namespace API.Controllers
{
    /// <summary>
    /// 代码生成
    /// </summary>
    public class BuildController : BaseController
    {
        ISqlSugarClient _db;
        public BuildController(ISqlSugarClient db)
        {
            _db = db;
        }
        string basePath = AppContext.BaseDirectory;//获取应用程序的基础目录
        [HttpPost]
        [AllowAnonymous]
        public async Task<ResultMsg<string>> BuildCode([FromBody] List<string>? tableList)
        {
            ResultMsg<string> result = new ResultMsg<string>();
            try
            {
                string strSql = string.Empty;
                List<TableField> list = new List<TableField>();
                if (tableList != null && tableList.Count > 0)
                {
                    // 输出表名称
                    foreach (var item in tableList)
                    {
                        list = new List<TableField>();
                        string tableName = item;
                        strSql = $@"-- 查询表 tGoodsCategorize 的所有列名、数据类型和描述
SELECT 
    c.name AS ColumnName,
    t.name AS DataType,
    COALESCE(ep.value, '') AS Comment
FROM 
    sys.columns c
JOIN 
    sys.tables t_table ON c.object_id = t_table.object_id
JOIN 
    sys.types t ON c.user_type_id = t.user_type_id
LEFT JOIN 
    sys.extended_properties ep ON c.object_id = ep.major_id AND c.column_id = ep.minor_id
WHERE 
    t_table.name = N'{tableName}'
ORDER BY 
    c.column_id;";
                        // 获取表的字段
                        DataTable columns = await _db.Ado.GetDataTableAsync(strSql, new { TableName = tableName });
                        list = ListHelper.DataTableToList<TableField>(columns);
                        CodeModel(list, tableName);
                        CodeSaveDto(list, tableName);
                        CodeGetListDto(list, tableName);
                        CodeDao(list, tableName);
                        CodeMapper(list, tableName);
                        CodeController(tableName);
                    }
                }
                else
                {

                }
                // 获取所有表的名称

                strSql = @"SELECT TABLE_NAME 
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE';";
                DataTable tableNames = _db.Ado.GetDataTable(strSql);
                // 输出表名称
                foreach (DataRow row in tableNames.Rows)
                {
                    list = new List<TableField>();
                    string tableName = (string)row["TABLE_NAME"];
                    strSql = $@"-- 查询表 tGoodsCategorize 的所有列名、数据类型和描述
SELECT 
    c.name AS ColumnName,
    t.name AS DataType,
    COALESCE(ep.value, '') AS Comment
FROM 
    sys.columns c
JOIN 
    sys.tables t_table ON c.object_id = t_table.object_id
JOIN 
    sys.types t ON c.user_type_id = t.user_type_id
LEFT JOIN 
    sys.extended_properties ep ON c.object_id = ep.major_id AND c.column_id = ep.minor_id
WHERE 
    t_table.name = N'{tableName}'
ORDER BY 
    c.column_id;";
                    // 获取表的字段
                    DataTable columns = await _db.Ado.GetDataTableAsync(strSql, new { TableName = tableName });
                    list = ListHelper.DataTableToList<TableField>(columns);
                    CodeModel(list, tableName);
                    CodeSaveDto(list, tableName);
                    CodeGetListDto(list, tableName);
                    CodeDao(list, tableName);
                    CodeMapper(list, tableName);
                    CodeController(tableName);
                }
                return result.Success();
            }
            catch (Exception ex)
            {
                Util.NLOG.LogHelper.Error("BuildController--BuildCode:" + ex.ToString());
                return result.Error(ex.ToString());
            }
        }

        [HttpPost]
        [AllowAnonymous]
        public async Task<ResultMsg<string>> BuildCode2([FromBody] List<string>? tableList)
        {
            ResultMsg<string> result = new ResultMsg<string>();
            try
            {
                List<TableField> list = new List<TableField>();

                if (tableList != null && tableList.Any())
                {
                    GenerateCodeForTables(tableList);
                }
                else
                {
                    // 获取所有表的名称
                    string strSql = @"SELECT TABLE_NAME 
                              FROM INFORMATION_SCHEMA.TABLES
                              WHERE TABLE_TYPE = 'BASE TABLE';";

                    DataTable tableNames = await _db.Ado.GetDataTableAsync(strSql);
                    List<string> allTableNames = new List<string>();
                    foreach (DataRow row in tableNames.Rows)
                    {
                        allTableNames.Add((string)row["TABLE_NAME"]);
                    }

                    GenerateCodeForTables(allTableNames);
                }

                return result.Success();
            }
            catch (Exception ex)
            {
                Util.NLOG.LogHelper.Error("BuildController--BuildCode:" + ex.ToString());
                return result.Error(ex.ToString());
            }
        }
        private void GenerateCodeForTables(List<string> tableList)
        {
            string strSql = @"-- 查询表的所有列名、数据类型和描述
SELECT 
    c.name AS ColumnName,
    t.name AS DataType,
    COALESCE(ep.value, '') AS Comment
FROM 
    sys.columns c
JOIN 
    sys.tables t_table ON c.object_id = t_table.object_id
JOIN 
    sys.types t ON c.user_type_id = t.user_type_id
LEFT JOIN 
    sys.extended_properties ep ON c.object_id = ep.major_id AND c.column_id = ep.minor_id
WHERE 
    t_table.name = @TableName
ORDER BY 
    c.column_id;"
            ;

            foreach (var tableName in tableList)
            {
                DataTable columns = _db.Ado.GetDataTable(strSql, new { TableName = tableName });
                var list = ListHelper.DataTableToList<TableField>(columns);
                CodeModel(list, tableName);
                CodeSaveDto(list, tableName);
                CodeGetListDto(list, tableName);
                CodeDao(list, tableName);
                CodeMapper(list, tableName);
                CodeController(tableName);
            }
        }
        private void CodeModel(List<TableField> list, string tableName)
        {
            List<string> unList = new List<string>()
            {
                "Id","CreateTime","CreatorId"
            };
            list = list.Where(c => !unList.Contains(c.ColumnName)).ToList();
            string properties = string.Empty;
            foreach (var item in list)
            {
                // 检查数据类型是否为 string，并相应地设置默认值
                string defaultValue = GetDataType(item.DataType) == "string" ? " = string.Empty" : "";
                properties += $@"
        /// <summary>
        /// {item.Comment}
        /// </summary>
        public {GetDataType(item.DataType)} {item.ColumnName} {{ get; set; }}{defaultValue}";
            }

            string codeStr = $@"
namespace HappyCenter.Model
{{
    /// <summary>
    /// 
    /// </summary>
    public class {tableName}:BaseEntity
    {{
        {properties}
    }}
}}";
            string directoryPath = Path.Combine(basePath, "Build/Models");
            string filePath = Path.Combine(directoryPath, tableName + ".cs");

            // 检查目录是否存在，如果不存在则创建
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            // 检查文件是否存在，如果存在则先删除
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
            }

            // 写入文件
            System.IO.File.WriteAllText(filePath, codeStr);

        }
        /// <summary>
        /// 获取数据类型
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        private string GetDataType(string dataType)
        {
            string str = string.Empty;
            switch (dataType)
            {
                case "varchar":
                    str = "string";
                    break;
                case "datetime":
                    str = "DateTime";
                    break;
                case "tinyint":
                    str = "int";
                    break;
                case "int":
                    str = "int";
                    break;
                case "bit":
                    str = "bool";
                    break;
                case "float":
                    str = "float";
                    break;
                case "double":
                    str = "double";
                    break;
                case "decimal":
                    str = "decimal";
                    break;

            }
            return str;
        }
        /// <summary>
        /// 生成SaveInput
        /// </summary>
        /// <param name="list"></param>
        /// <param name="tableName"></param>
        private void CodeSaveDto(List<TableField> list, string tableName)
        {
            List<string> unList = new List<string>()
            {
                "CreateTime","CreatorId"
            };
            list = list.Where(c => !unList.Contains(c.ColumnName)).ToList();
            string className = "Save" + tableName.Substring(1, tableName.Length - 1);
            string propertyName = string.Empty;
            string properties = string.Empty;
            foreach (var item in list)
            {
                string defaultValue = GetDataType(item.DataType) == "string" ? " = string.Empty" : "";
                propertyName = item.ColumnName == "Id" ? "Id" : item.ColumnName.Substring(1, item.ColumnName.Length - 1);
                properties += $@"
        /// <summary>
        /// {item.Comment}
        /// </summary>
        public {GetDataType(item.DataType)} {propertyName} {{ get; set; }}{defaultValue}";
            }

            string codeStr = $@"
namespace HappyCenter.Dto
{{
    /// <summary>
    /// 
    /// </summary>
    public class {className}Input
    {{
        {properties}
    }}
}}";
            string directoryPath = Path.Combine(basePath, "Build/Input");
            string filePath = Path.Combine(directoryPath, className + "Input.cs");

            // 检查目录是否存在，如果不存在则创建
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            // 检查文件是否存在，如果存在则先删除
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
            }

            // 写入文件
            System.IO.File.WriteAllText(filePath, codeStr);

        }

        /// <summary>
        /// 生成GetListInput
        /// </summary>
        /// <param name="list"></param>
        /// <param name="tableName"></param>
        private void CodeGetListDto(List<TableField> list, string tableName)
        {
            List<string> unList = new List<string>()
            {
                "CreateTime","CreatorId","Id"
            };
            list = list.Where(c => !unList.Contains(c.ColumnName)).ToList();
            string className = tableName.Substring(1, tableName.Length - 1) + "ListInput";
            string properties = string.Empty;
            string propertyName = string.Empty;
            foreach (var item in list)
            {
                string defaultValue = GetDataType(item.DataType) == "string" ? " = string.Empty" : "";
                propertyName = item.ColumnName == "Id" ? "Id" : item.ColumnName.Substring(1, item.ColumnName.Length - 1);
                properties += $@"
        /// <summary>
        /// {item.Comment}
        /// </summary>
        public {GetDataType(item.DataType)} {propertyName} {{ get; set; }} {defaultValue}";
            }

            string codeStr = $@"
using HappyCenter.Utils;

namespace HappyCenter.Dto
{{
    /// <summary>
    /// 
    /// </summary>
    public class {className}:BasePaging
    {{
        {properties}
    }}
}}";
            string directoryPath = Path.Combine(basePath, "Build/Input");
            string filePath = Path.Combine(directoryPath, className + ".cs");

            // 检查目录是否存在，如果不存在则创建
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            // 检查文件是否存在，如果存在则先删除
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
            }

            // 写入文件
            System.IO.File.WriteAllText(filePath, codeStr);

        }

        /// <summary>
        /// 生成Output
        /// </summary>
        /// <param name="list"></param>
        /// <param name="tableName"></param>
        private void CodeDao(List<TableField> list, string tableName)
        {
            List<string> unList = new List<string>()
            {
                "CreateTime","CreatorId" 
            };
            list = list.Where(c => !unList.Contains(c.ColumnName)).ToList();
            string className = tableName.Substring(1, tableName.Length - 1) + "Output";
            string properties = string.Empty;
            string propertyName = string.Empty;
            foreach (var item in list)
            {
                string defaultValue = GetDataType(item.DataType) == "string" ? " = string.Empty" : "";
                propertyName = item.ColumnName == "Id" ? "Id" : item.ColumnName.Substring(1, item.ColumnName.Length - 1);
                properties += $@"
        /// <summary>
        /// {item.Comment}
        /// </summary>
        public {GetDataType(item.DataType)} {propertyName} {{ get; set; }} {defaultValue}";
            }

            string codeStr = $@"
using HappyCenter.Utils;
namespace HappyCenter.Dao
{{
    /// <summary>
    /// 
    /// </summary>
    public class {className}
    {{
        {properties}
    }}
}}";
            string directoryPath = Path.Combine(basePath, "Build/Output");
            string filePath = Path.Combine(directoryPath, className + ".cs");

            // 检查目录是否存在，如果不存在则创建
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            // 检查文件是否存在，如果存在则先删除
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
            }

            // 写入文件
            System.IO.File.WriteAllText(filePath, codeStr);

        }
        /// <summary>
        /// 追加AutoMapper
        /// </summary>
        /// <param name="list"></param>
        /// <param name="tableName"></param>
        private void CodeMapper(List<TableField> list, string tableName)
        {
            List<string> unList = new List<string>()
            {
                "CreateTime","CreatorId"
            };
            list = list.Where(c => !unList.Contains(c.ColumnName)).ToList();
            string classSave = "Save" + tableName.Substring(1, tableName.Length - 1) + "Input";
            string classDao = tableName.Substring(1, tableName.Length - 1) + "Output";
            string properties = string.Empty;
            string propertyName = string.Empty;
            properties += $@"CreateMap<{classSave}, {tableName}>()";
            foreach (var item in list)
            {
                propertyName = item.ColumnName == "Id" ? "Id" : item.ColumnName.Substring(1, item.ColumnName.Length - 1);
                properties += $@".ForMember(dest => dest.{item.ColumnName}, opt => opt.MapFrom(src => src.{propertyName}))";
            }
            properties += $@";";
            propertyName = string.Empty;
            properties += $@"CreateMap<{tableName}, {classDao}>()";
            foreach (var item in list)
            {
                propertyName = item.ColumnName == "Id" ? "Id" : item.ColumnName.Substring(1, item.ColumnName.Length - 1);
                properties += $@".ForMember(dest => dest.{propertyName}, opt => opt.MapFrom(src => src.{item.ColumnName}))";
            }
            properties += $@";";

            string directoryPath = Path.Combine(basePath, "Build/AutoMapper");
            string filePath = Path.Combine(directoryPath,  "AutoMapperProfile.cs");
            //string filePath = @"D:\公司项目\backend-microservices\HappyCenter\Build\Mapper\AutoMapperProfile.cs";

            try
            {
                // 读取现有文件内容
                string content = System.IO.File.ReadAllText(filePath);

                // 查找要插入代码的位置
                int insertionPoint = content.IndexOf("//在这里插入数据");

                // 如果找到了位置
                if (insertionPoint >= 0)
                {
                    // 计算插入点后的索引（跳过注释）
                    int insertionAfterComment = insertionPoint + "//在这里插入数据".Length;

                    // 分割文件内容
                    string beforeInsertion = content.Substring(0, insertionAfterComment);
                    string afterInsertion = content.Substring(insertionAfterComment);

                    // 创建新的文件内容
                    StringBuilder newContent = new StringBuilder();
                    string removeMarker = "//在这里插入数据";// 删除所有 "//在这里插入数据" 的实例
                    while (beforeInsertion.Contains(removeMarker))
                    {
                        int markerIndex = beforeInsertion.IndexOf(removeMarker);
                        beforeInsertion = beforeInsertion.Remove(markerIndex, removeMarker.Length);
                    }
                    newContent.Append(beforeInsertion);
                    newContent.Append(Environment.NewLine); // 添加换行符
                    newContent.Append(properties);
                    newContent.Append(Environment.NewLine); // 添加换行符


                    while (afterInsertion.Contains(removeMarker))
                    {
                        int markerIndex = afterInsertion.IndexOf(removeMarker);
                        afterInsertion = afterInsertion.Remove(markerIndex, removeMarker.Length);
                    }
                    newContent.Append("//在这里插入数据");
                    newContent.Append("\r\n"); // 添加换行符
                    newContent.Append(afterInsertion);

                    // 写入新的文件内容
                    System.IO.File.WriteAllText(filePath, newContent.ToString());
                }
                else
                {
                    Util.NLOG.LogHelper.Info("未找到指定的位置。");
                }
            }
            catch (Exception ex)
            {
                Util.NLOG.LogHelper.Info($"发生错误: {ex.Message}");
            }

        }
        /// <summary>
        /// 生成Controller
        /// </summary>
        /// <param name="list"></param>
        /// <param name="tableName"></param>
        private void CodeController(string tableName)
        {
            string className = tableName.Substring(1, tableName.Length - 1) + "Controller";
            string repository = "_" + tableName.Substring(1, tableName.Length - 1);
            string mintTable = tableName.Substring(1, tableName.Length - 1);

            string classSave = "Save" + tableName.Substring(1, tableName.Length - 1) + "Input";
            string classListDto = tableName.Substring(1, tableName.Length - 1) + "ListInput";
            string classDao = tableName.Substring(1, tableName.Length - 1) + "Output";
            string returnDao = tableName.Substring(1, tableName.Length - 1) + "Outputs";
            string codeStr = $@"using AutoMapper;
using HappyCenter.Dao;
using HappyCenter.Dto;
using HappyCenter.Model;
using HappyCenter.Utils;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace HappyCenter.Controllers
{{
    public class {className} : BaseController
    {{
        Repository<{tableName}> {repository};
        readonly IMapper _mapper;
        public {className}(Repository<{tableName}> {mintTable}, IMapper mapper)
        {{
            {repository} = {mintTable};
            _mapper = mapper;
        }}
        /// <summary>
        /// 保存
        /// </summary>
        /// <param name=""dto""></param>
        /// <returns></returns>
        [HttpPost]
        public ResultMsg<string> Save([FromBody] {classSave} dto)
        {{
            ResultMsg<string> result = new ResultMsg<string>();
            try
            {{
                var model = _mapper.Map<{tableName}>(dto);
                InitEntity(model);
                {repository}.InsertOrUpdateAsync(model);
                return result.Success();
            }}
            catch (Exception ex)
            {{
                Util.NLOG.LogHelper.Error(""{className}--Save:"" + ex.ToString());
                return result.Error(ex.ToString());
            }}
        }}

        /// <summary>
        /// 获取列表
        /// </summary>
        /// <param name=""dto""></param>
        /// <returns></returns>
        [HttpPost]
        public ResultMsg<List<{classDao}>> GetList([FromBody] {classListDto} dto)
        {{
            ResultMsg<List<{classDao}>> result = new ResultMsg<List<{classDao}>>();
            try
            {{
                if (dto.PageNum <= 0)
                {{
                    return result.Error(""PageNum不能小于或等于0"");
                }}
                if (dto.PageSize <= 0)
                {{
                    return result.Error(""PageSize不能小于或等于0"");
                }}
                SqlSugar.PageModel pageModel = new SqlSugar.PageModel
                {{
                    PageIndex = dto.PageNum,
                    PageSize = dto.PageSize,
                }};
                var exp = Expressionable.Create<{tableName}>();
                if (!string.IsNullOrWhiteSpace(dto.Name))
                {{
                    exp.And(x => x.FName.Contains(dto.Name));
                }}
                var list = {repository}.GetPageList(exp.ToExpression(), pageModel).OrderByDescending(x => x.CreateTime).ToList();
                var {returnDao} = _mapper.Map<List<{classDao}>>(list);
                return result.Success({returnDao}, pageModel.TotalCount);
            }}
            catch (Exception ex)
            {{
                Util.NLOG.LogHelper.Error(""{className}--GetList:"" + ex.ToString());
                return result.Error(ex.ToString());
            }}
        }}
        /// <summary>
        /// 获取唯一
        /// </summary>
        /// <param name=""id"">主键ID</param>
        /// <returns></returns>
        [HttpGet]
        public ResultMsg<{classDao}> GetTheOne(string id)
        {{
            ResultMsg<{classDao}> result = new ResultMsg<{classDao}>();
            try
            {{
                var model = {repository}.GetById(id);
                var dao = _mapper.Map<{classDao}>(model);
                return result.Success(dao);
            }}
            catch (Exception ex)
            {{
                Util.NLOG.LogHelper.Error(""{className}--GetTheOne:"" + ex.ToString());
                return result.Error(ex.ToString());
            }}
        }}
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name=""id"">主键ID</param>
        /// <returns></returns>
        [HttpGet]
        public ResultMsg<string> Del(string id)
        {{
            ResultMsg<string> result = new ResultMsg<string>();
            try
            {{
                {repository}.DeleteById(id);
                return result.Success();
            }}
            catch (Exception ex)
            {{
                Util.NLOG.LogHelper.Error(""{className}--Del:"" + ex.ToString());
                return result.Error(ex.ToString());
            }}
        }}
    }}
}}
";
            string directoryPath = Path.Combine(basePath, "Build/Controller");
            //string directoryPath = "D:/公司项目/backend-microservices/HappyCenter/Build/Controller";
            string filePath = Path.Combine(directoryPath, className + ".cs");

            // 检查目录是否存在，如果不存在则创建
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            // 检查文件是否存在，如果存在则先删除
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
            }

            // 写入文件
            System.IO.File.WriteAllText(filePath, codeStr);

        }
    }
}
